#ifndef REMOVE_H_
#define REMOVE_H_

#include "vehicleState.h"
#include "tabooList.h"
#include "gMatrix.h"
#include "los.h"

/** Numero di iterazioni di tenure per gli archi aggiunti nella mossa REMOVE triangolante. */
#define REMOVE_ADDTENURE 2
/** Numero di iterazioni di tenure per gli archi rimossi nella mossa REMOVE triangolante. */
#define REMOVE_REMTENURE 1

/** ridefinire questo tra PURE, SMART, WISE per cambiare la logica di REMOVE. */
#define EVAL_REMOVE_PROFITABLES EVAL_SMART
/** ridefinire questo tra PURE, WISE per cambiare la logica di REMOVE verso gli archi non profittabili. */
#define EVAL_REMOVE_NON_PROFITABLES EVAL_PURE

/**computa l'intorno della soluzione tramite un intorno remove e ricava il migliore stato possibile per il veicolo.
 *
 * @param graph indica il grafo su cui computare il nuovo intorno. Non inserire valore NULL
 * @param now è l'iterazione STM corrente, usata per approciarsi alla taboolist.
 * @param vehicleState indica lo stato di un veicolo, utilizzato come centro dell'intorno. Non inserire valore NULL.
 * 			Attenzione: questo stato, a meno che la mossa fallisca (supponiamo possa fallire per mille motivi) sarà MODIFICATO.
 * @param k l'identificativo del veicolo interessato al REMOVE. Richiesto nel confronto sulla matrice G.
 * @param tabooList indica la tabulist che include alcuni divieti su alcuni archi. Non inserire valore NULL
 * @param pLOSconfig la configurazione LOS utilizzata dalla mossa.
 * @param notWorseningMoves filtra i candidati sui soli miglioranti lo stato o che lo lascino invariato (sempre solo a livello di profit), sse posto a true.
 * @return MOVE_STATUS_OK sse una mossa viene effettivamente eseguita; MOVE_STATUS_FAIL altrimenti.
 */
int solveRemoveNeighbourhood(Pgraph p_graph, PvehicleState p_state, PGMatrix p_gMat, int k, PtabooList p_tabooList, TabooExpire now,
							pLOSConfiguration pLOSconfig, bool notWorseningMoves);

/** Mossa finale e confermata. Non ha precondizioni non banali perchè viene effettuata quando si è già certi che sia feasible */
void makeRemoveMove(Pgraph p_graph, PvehicleState p_state, PGMatrix p_gMat, int k, PtabooList p_tabooList, TabooExpire now, PbestAddRemoveChoice p_best, int addTenure, int removeTenure);

/** Snellimento del codice. aggiorna una scelta migliore, \ref{BestChoice} */
void updateBestRemoveChoice(PbestAddRemoveChoice p_bestchoice, EdgeID e_il, EdgeID e_jl, EdgeID e_ij, Weight score);

/** analizza gli effetti sull'improvement di un possibile candidato di tipo arco triangolante (se feasible)
 * cosa deve assicurarsi?
 * \li l'arco non sia percorso
 * \li aggiungendolo si resti TQOK
 * \li la modifica sia concessa dalla TL o dai criteri
 * @param p_edge arco 'perno' del triangolo.
 * @param p_sx parte 'sinistra' della triangolazione
 * @param p_dx parte 'destra' della triangolazione.
 * @param times_il numero di percorrenze del percorso del veicolo k-esimo, per l'arco il
 * @param times_jl numero di percorrenze del percorso del veicolo k-esimo, per l'arco jl
 * @param evaluateMoves flag di selezione tra i criteri di valutazione (sostituisce vecchio sistema di macros)
 * @return 0 sse il candidato non è ammissibile (taboo, non TQok) */
Weight analyzeTriangleEdgeRemoveCandidate(Pgraph p_graph, PedgeID pid_ij, PedgeID pid_il, PedgeID pid_jl,
									 PvehicleState p_state, PGMatrix p_gMat, int k, PtabooList p_tabooList, TabooExpire now,
									 int times_il, int times_jl, int evaluateMode);

/**controlla se una mossa di tipo REMOVE modalita' triangolante è accettabie secondo i criteri T e Q del grafo.
 * contrariamente a quanto detto velocemente in fase di progettazione infatti, anche i remove possono non essere TQOK, se l'arco triangolante
 * inserito ha richieste che non possono esser più soddisfatte in termini di Q (difatti T è sempre feasible, per la disuguaglianza triangolare)
 *
 * @param graph indica il grafo su cui deve essere applicata la mossa REMOVE
 * @param state indica lo stato del veicolo su cui aplicare la mossa REMOVE
 * @param toadd1 indica l'arco e_ij da aggiungere al percorso
 * @param toremove1 indica l'arco e_il da rimuovere al percorso
 * @param toremove2 indica l'arco e_jl da rimuovere al percorso
 * @param pgm un riferimento alla matrice ove controllare la raccoglibilità dell'edge: se non è possibile, è incorretto considerarla.
 * @return true sse la mossa triangolante è TQOK.
 */
bool isTQOKTriangleRemove(Pgraph graph, PvehicleState state, PGMatrix p_gMat, PedgeID toadd, PedgeID toremove1, PedgeID toremove2, int k);

#endif /* ADD_H_ */
